package com.grid.camera.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

@Slf4j
public class NettyClient {

    private final DataReceiveListener dataReceiveListener;
    // 连接主机端口
    private final Integer port;
    // 连接主机ip
    private final String host;
    // 响应数据队列
    public EventLoopGroup group;
    public Channel channel;
    public ChannelFuture channelFuture;

    public NettyClient(String host, Integer port, DataReceiveListener dataReceiveListener) {
        this.host = host;
        this.port = port;
        this.dataReceiveListener = dataReceiveListener;
    }

    /** 关闭客户端连接并释放资源 */
    public void close() {
        try {
            // 关闭通道
            if (channel != null) {
                channel.close().sync();
                channel = null;
            }

            // 关闭线程组
            if (group != null && !group.isShutdown()) {
                group.shutdownGracefully();
                group = null;
            }

            log.info("NettyClient已关闭");
        } catch (Exception e) {
            log.error("关闭NettyClient异常：{}", e.getMessage());
        }
    }

    /** 创建TCP长连接并实例化channel */
    public void connect() {

        // 确保之前的资源已经释放
        if (channel != null) {
            channel.close();
            channel = null;
        }
        if (group != null && !group.isShutdown()) {
            group.shutdownGracefully();
            group = null;
        }

        try {

            group = new NioEventLoopGroup();

            Bootstrap bootstrap = new Bootstrap();
            bootstrap
                    // 1 设置reactor 线程
                    .group(group)
                    .option(ChannelOption.TCP_NODELAY, true)
                    // 1 设置通道选项
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    // 2 设置nio类型的channel
                    .channel(NioSocketChannel.class)
                    // 3 装配流水线
                    .handler(new ClientChannelInitializer(NettyClient.this));
            // 创建连接
            channelFuture = bootstrap.connect(host, port);

            // 检测并执行断线重连
            channelFuture.addListener(
                    (ChannelFutureListener)
                            channelFuture -> {
                                if (!channelFuture.isSuccess()) {
                                    final EventLoop loop = channelFuture.channel().eventLoop();
                                    loop.schedule(
                                            () -> {
                                                log.error(host + " ： 服务端链接不上，开始重连操作...");
                                                connect();
                                                // 此处处理重连次数
                                            },
                                            1L,
                                            TimeUnit.SECONDS);
                                } else {
                                    channel = channelFuture.channel();
                                    log.info("服务端链接成功...");
                                }
                            });

            channel = channelFuture.channel();
        } catch (Exception e) {
            log.error("服务端链接异常：{}", e.getMessage());
        }
    }

    /**
     * 检查客户端是否已连接
     *
     * @return 是否已连接
     */
    public boolean isConnected() {
        if (channel == null) {
            return false;
        }
        return channel.isActive();
    }

    public void onReceiveData(String ip, byte[] data) {

        // 将接收到的数据放入队列
        if (dataReceiveListener != null) {
            dataReceiveListener.onDataReceived(ip, data);
        }
    }
}
